<!DOCTYPE html>
<html>

  <head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <title>雕虫晓技(四) 诡异的空指针</title>
  <meta name="description" content="多线程中诡异的空指针，用 final 局部变量指向全局变量可以解决该问题。">
  <meta name="author" content="GcsSloop">
  <meta name="keywords" content="Android">
  <meta name="关键字" content="Android">
  

  <meta name="twitter:card" content="summary">
  <meta name="twitter:title" content="雕虫晓技(四) 诡异的空指针">
  <meta name="twitter:description" content="多线程中诡异的空指针，用 final 局部变量指向全局变量可以解决该问题。">
  <meta name="twitter:keywords" content="Android">
  
  <meta property="og:type" content="article">
  <meta property="og:title" content="雕虫晓技(四) 诡异的空指针">
  <meta property="og:description" content="多线程中诡异的空指针，用 final 局部变量指向全局变量可以解决该问题。">
  <meta name="og:keywords" content="Android">

  <meta name="theme-color" content="#343434">
  
  <link rel="icon" type="image/png" href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" />
  <link href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" rel="shortcut icon" type="image/png">
  
  <link href="//netdna.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/css/main.css">

  <link rel="canonical" href="http://www.gcssloop.com/gebug/nullpointer-exception">
  <link rel="alternate" type="application/rss+xml" title="GcsSloop" href="http://www.gcssloop.com/feed.xml">
  
  <meta name="google-site-verification" content="Z_g58PkzRAyBMxkqrcDdWrTBK8oOWM-7rUHauhLNF2E" />
  <meta name="baidu-site-verification" content="kUtTXCKaZs" />
  <meta name="baidu-site-verification" content="6DuDv3aaJX" />
  
  <!--阅读次数统计-->
  <script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"> </script>
  
  <!--Fuck Weixin and Baidu-->
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta http-equiv=”Cache-Control” content=”no-siteapp” />
  <meta name="applicable-device" content="pc,mobile">
  <meta name="HandheldFriendly" content="true"/>

</head>


  <body>

    <span class="mobile btn-mobile-menu">
        <i class="fa fa-list btn-mobile-menu__icon"></i>
        <i class="fa fa-angle-up btn-mobile-close__icon hidden"></i>
    </span>
    
    <header class="panel-cover panel-cover--collapsed" style="background-image: url('/assets/siteinfo/background-cover.jpg')">
  <div class="panel-main">

    <div class="panel-main__inner panel-inverted">
    <div class="panel-main__content">

        <a href="/#blog" title="前往 GcsSloop 的主页" class="blog-button"><img src="/assets/siteinfo/avatar.jpg" width="80" alt="GcsSloop logo" class="panel-cover__logo logo" /></a>
        <h1 class="panel-cover__title panel-title"><a href="/#blog" title="link to homepage for GcsSloop" class="blog-button">GcsSloop</a></h1>

        
        <span class="panel-cover__subtitle panel-subtitle">Just do IT later.</span>
        
        <hr class="panel-cover__divider" />
        <p class="panel-cover__description">嗨，我是 GcsSloop，一名来自2.5次元的魔法师，Android自定义View系列文章作者，非著名程序员。</p>
        <hr class="panel-cover__divider panel-cover__divider--secondary" />
        
        
        <p class="panel-cover__description">欢迎来到我的魔法世界!</p>
        
        
        <div class="navigation-wrapper">
          <div>
            <nav class="cover-navigation cover-navigation--primary">
              <ul class="navigation">
                <li class="navigation__item"><a href="/#blog" title="访问博客" class="blog-button">博客</a></li>
                
                  
                    <li class="navigation__item"><a href="https://github.com/GcsSloop" target="_blank" title="GcsSloop's GitHub">GitHub</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/timeline" title="博客目录">目录</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="https://xiaozhuanlan.com/u/GcsSloop" target="_blank" title="小专栏">专栏</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/customview/CustomViewIndex" title="自定义View教程目录">自定义控件</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/info/about" title="关于作者 GcsSloop">关于</a></li>
                  
                  
                
              </ul>
            </nav>
          </div>
          
          <div><nav class="cover-navigation navigation--social">
  <ul class="navigation">

  
  <!-- Weibo -->
  <li class="navigation__item">
    <a href="http://weibo.com/GcsSloop" title="@GcsSloop 的微博" target="_blank">
      <i class='social fa fa-weibo'></i>
      <span class="label">Weibo</span>
    </a>
  </li>
  

  
  <!-- Github -->
  <li class="navigation__item">
    <a href="https://github.com/GcsSloop" title="@GcsSloop 的 Github" target="_blank">
      <i class='social fa fa-github'></i>
      <span class="label">Github</span>
    </a>
  </li>
  
  
  
  <!-- Twitter -->
  <li class="navigation__item">
    <a href="http://twitter.com/GcsSloop" title="@GcsSloop" target="_blank">
      <i class='social fa fa-twitter'></i>
      <span class="label">Twitter</span>
    </a>
  </li>
  

    

  

  
  <!-- RSS -->
  <li class="navigation__item">
    <a href="/feed.xml" rel="author" title="RSS" target="_blank">
      <i class='social fa fa-rss'></i>
      <span class="label">RSS</span>
    </a>
  </li>
  

  
  <!-- Email -->
  <li class="navigation__item">
    <a href="mailto:GcsSloop@gmail.com" title="发邮件给我">
      <i class='social fa fa-envelope'></i>
      <span class="label">Email</span>
    </a>
  </li>
  

  
  <!-- Copyright -->
  <li class="navigation__item">
    <a href="http://choosealicense.online" title="选择版权"  target="_blank">
      <i class="social fa fa-copyright"></i>
      <span class="label">版权</span>
    </a>
  </li>
  
  
  </ul>
</nav>
</div>
        </div>
      </div>
    </div>
    
    
    <div class="panel-cover--overlay cover-slate"></div>
    
  </div>
</header>


    <div class="content-wrapper">
        <div class="content-wrapper__inner">
            <article class="post-container post-container--single" itemscope itemtype="http://schema.org/BlogPosting">
  <header class="post-header">
    <div class="post-meta" style="font-size:.8em">
      <time datetime="2018-01-01 00:00:00 +0800" itemprop="datePublished" class="post-meta__date date">2018-01-01</time> &#8226; <span class="post-meta__tags tags">Android</span> &#8226; View <span id="busuanzi_value_page_pv"></span> times.
</span>
    </div>
    <h1 class="post-title">雕虫晓技(四) 诡异的空指针</h1>
  </header>

  <section class="post">
    <h3 id="关于作者">关于作者</h3>

<p>GcsSloop，一名 2.5 次元魔法师。<br />
<a href="http://weibo.com/GcsSloop/home">微博</a> | <a href="https://github.com/GcsSloop">GitHub</a> | <a href="http://www.gcssloop.com/">博客</a></p>

<p><img src="https://ww3.sinaimg.cn/large/006tNc79gy1fl8bemmtmxj30p005k406.jpg" alt="" /></p>

<h2 id="前言">前言</h2>

<p>这件事情呢，要从一段简单的代码说起，还记得那是一个风和日丽的下午，我熟练的打开了陪伴我多年的IDE，看着那熟悉的界面，我开开心心的写下了如下的代码：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="n">String</span> <span class="n">mStr</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>

<span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">printStrLength</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="kc">null</span> <span class="o">!=</span> <span class="n">mStr</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">mStr</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"length = "</span> <span class="o">+</span> <span class="n">len</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>

<p>我有一个全局的变量 mStr，我想要输出它的长度，于是我写了这样一个方法，这种问题对于我这样的老司机来说，自然是很 Easy 的，相信大家从  <code class="highlighter-rouge">if (null != mStr)</code> 就已经看出了我是一个经验丰富的专家，时刻提防着空指针来破坏我的代码运行。</p>

<p>当我自信的按下运行按钮时，不可思议的事情发生了，我的代码居然出现了异常，居然是空指针，并且发生在几乎是不可能出现的位置。</p>

<p><img src="https://ww2.sinaimg.cn/large/006tKfTcgy1fn0gdzt8c6j30gp08rq4i.jpg" alt="" /></p>

<p>这不是我的错，一定是运行时出现了问题，沉思片刻后，我决定再试一次！</p>

<p>当相同的错误在此出现的时候，我发觉了，这一定是 IDE 出现了 bug，于是我决定重启一下我的 IntelliJ IEAD。</p>

<p>当 IDE 重启完毕，我再次运行，发现错误依旧出现，此时我觉得可能是我的电脑太古老了，也许应该换一台试试，当然，也有可能是我的 java 虚拟机坏掉了 …</p>

<h2 id="诡异的空指针">诡异的空指针</h2>

<p>说到空指针，这应该是 java 语言中最常见，也是最让人头疼的异常之一了，上面和大家开个玩笑，其实这个空指针异常是我精心制造出来的，就是因为他比较有趣，不仅触发方式有趣，解决方式也很有趣。</p>

<p>下面给大家看一下制造这个空指针异常的完整代码：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">GcsTest</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="n">String</span> <span class="n">mStr</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">printStrLength</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="kc">null</span> <span class="o">!=</span> <span class="n">mStr</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">mStr</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
            <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"length = "</span> <span class="o">+</span> <span class="n">len</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">GThreadA</span> <span class="n">threadA</span> <span class="o">=</span> <span class="k">new</span> <span class="n">GThreadA</span><span class="o">();</span>
        <span class="n">GThreadB</span> <span class="n">threadB</span> <span class="o">=</span> <span class="k">new</span> <span class="n">GThreadB</span><span class="o">();</span>
        <span class="n">threadA</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
        <span class="n">threadB</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
    <span class="o">}</span>

    <span class="kd">static</span> <span class="kd">class</span> <span class="nc">GThreadA</span> <span class="kd">extends</span> <span class="n">Thread</span> <span class="o">{</span>
        <span class="nd">@Override</span>
        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span>
            <span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="kc">null</span> <span class="o">==</span> <span class="n">mStr</span><span class="o">)</span> <span class="o">{</span>
                    <span class="n">mStr</span> <span class="o">=</span> <span class="s">"Gcs"</span><span class="o">;</span>
                <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                    <span class="n">mStr</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>

    <span class="kd">static</span> <span class="kd">class</span> <span class="nc">GThreadB</span> <span class="kd">extends</span> <span class="n">Thread</span> <span class="o">{</span>
        <span class="nd">@Override</span>
        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span>
            <span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">printStrLength</span><span class="o">();</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>

<p>代码并不复杂，本质上就是两个线程，第一个线程(GThreadA)负责不断修改 <code class="highlighter-rouge">mStr</code> 的状态，第二个线程(GThreadB)则不断调用 <code class="highlighter-rouge">printStrLength()</code> 方法，尝试输出 mStr 的长度。</p>

<p>如果正常运行的话，输出结果应该是下面这样的：</p>

<div class="language-shell highlighter-rouge"><pre class="highlight"><code>length <span class="o">=</span> 3
length <span class="o">=</span> 3
length <span class="o">=</span> 3
length <span class="o">=</span> 3
length <span class="o">=</span> 3
length <span class="o">=</span> 3
length <span class="o">=</span> 3
...
</code></pre>
</div>

<p>但是，你运行的时候就会发现，它几乎是一定会出现空指针异常的，有时可能会正常运行一段时间后再出现，有时刚开始运行就出现了。</p>

<p>这个问题表面是空指针引起的，但核心是线程并发问题。观察下面这段代码，是没有任何问题的，在单线程上运行时，它是安全的代码，但遇到多线程并发就不一定了。</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">printStrLength</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="kc">null</span> <span class="o">!=</span> <span class="n">mStr</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">mStr</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"length = "</span> <span class="o">+</span> <span class="n">len</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>

<p>由于线程可能在任意位置中断并切换到其它线程，所以就可能出现如下这种情况：</p>

<p><strong>当 threadB 刚判断完 if(null != mStr) 这句话之后，切换到了 threadA，此时 threadA 也判断 mStr 不为 null，于是将 mStr 置为了 null，之后再切换到 threadB，当 threadB 获取长度的时候就发生了空指针异常。在并发的情况下执行顺序可能是这样的：</strong></p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">//前置条件： mStr 不为 null</span>
<span class="c1">//threadB</span>
<span class="k">if</span><span class="o">(</span><span class="kc">null</span> <span class="o">!=</span> <span class="n">mStr</span><span class="o">){</span>
<span class="c1">//切换线程到 threadA</span>
  <span class="k">if</span><span class="o">(</span><span class="kc">null</span> <span class="o">==</span> <span class="n">mStr</span><span class="o">){</span>
    <span class="o">...</span>
  <span class="o">}</span> <span class="k">else</span><span class="o">{</span>
    <span class="n">mStr</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
  <span class="o">}</span>
<span class="c1">//切换线程到 threadB</span>
  <span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">mStr</span><span class="o">.</span><span class="na">length</span><span class="o">();</span> <span class="c1">// &lt;-- 发生异常</span>
<span class="o">}</span>
</code></pre>
</div>

<p>现在我们已经知道问题的根源了，就是线程可能在代码执行的任意位置切换，如果在切换之后一些全局状态改变了，那么切换回来之后之前的判断条件其实是无效的。</p>

<p>既然发现了问题的根源，那就容易解决了，多线程并发问题，要不加个锁试试？但是仔细想想这个锁应该怎么加呢？</p>

<p>首先两个线程访问的是不同的代码块，不存在访问冲突，那么方法锁和类锁基本可以判断是无效的。</p>

<p>两个线程唯一共用的对象就是 mStr，所以看起来比较靠谱的方案就是把 mStr 这个对象锁起来，但是 mStr 又可能为 null，如果 mStr 为 null，那么加对象锁的时候就会直接抛出空指针异常！所以加锁之前最好用先判断 mStr 不为 null 再加锁。</p>

<p>额，再想想，这个和上面的操作有啥区别，由于多线程可能在任意位置切换，所以不论在哪里加 if 条件基本都形同虚设，这个简单的问题难道就无解了？</p>

<p><img src="https://ww3.sinaimg.cn/large/006tKfTcgy1fn0gdyaqe5j306y054myk.jpg" alt="" /></p>

<h2 id="解决方案">解决方案</h2>

<p>其实在这里加锁并不能解决问题，也不是一种好方案，众所周知，加锁的本质上是资源访问互斥，即当一个线程操作时进行锁定，在锁定期间其它任何线程都不允许访问，所以加锁会影响程序运行的性能，因此在非必要的情况下，能不用锁就尽量不用。</p>

<p>而且在上面这段代码中，mStr 是不断进行变化的，它的变化不应该受到外界操作的影响。举一个不太恰当的例子：
天气是不断变化的，我在天气好的时候出门逛街，天气不好的时候呆在家里打游戏，我根据天气状况来决定自己的活动，但是我是不能影响天气的，不能说，现在天气很好，我出门去逛街，为了防止突然下雨把我淋湿，我就把天气状态锁定到当前的好天气状态，当我逛完街回来，再释放天气状态，让天气继续变化。这显然即不符合逻辑也行不通。</p>

<p>在 Android 中一个比较类似的事情就是事件机制，只要用户在触摸，就不断会有事件产生，不论你是否使用，这些事件都在不断的产生，作为一个程序，并不能因为自己需要当前这一时刻的事件，就把事件锁定，不让其产生新的触摸事件。</p>

<p><strong>实质上，我们需要的仅仅是当下这一时刻的状态，并根据当下这一时刻的状态来决定我们接下来要做什么。</strong></p>

<p>分析完问题的本质，问题就已经解决了，我们需要的是当下这一刻的状态，那么把这一刻的状态保存下来不就行了？只用简单的修改一下代码，就能实现这一需求了：</p>

<p><strong>先使用一个 final 的局部变量指向全局变量，之后再对这个变量进行操作。</strong></p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">printStrLength</span><span class="o">()</span> <span class="o">{</span>
    <span class="c1">// 使用 final 关键字保存当前状态</span>
    <span class="kd">final</span> <span class="n">String</span> <span class="n">str</span> <span class="o">=</span> <span class="n">mStr</span><span class="o">;</span>
    <span class="k">if</span> <span class="o">(</span><span class="kc">null</span> <span class="o">!=</span> <span class="n">str</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">str</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"length = "</span> <span class="o">+</span> <span class="n">len</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>

<p><strong>我们这里使用 final 关键字将当前状态快照下来并用一个局部变量保存，之后的所有操作都只访问这个局部变量，由于这个局部变量是不会变化的，所以，即便发生上面的那种情况，判断完 if 条件后，线程切换出去改变了全局变量的状态，也不会影响到后续的操作。这也算是 final 关键字取巧的一种用法吧。</strong></p>

<h2 id="结语">结语</h2>

<p>其实你阅读 Android 源码的话，是经常可以见到使用一个 final 局部变量指向全局变量这种写法的，起初看到这种写法甚是不解，感觉这不是多此一举吗？直到我遇见了上面这种诡异的异常，才明白这种写法的精妙之处。</p>

<p>本文虽然啰嗦了那么多内容，其实本质上总结起来就一句话：<strong>使用 final 关键字快照当前全局变量的状态，可以防止特定情况下的多线程并发问题。</strong></p>

<p>虽然这是一种好方法，但也只是适用于特定的情况，并非万金油，当遇到问题时还是需要根据具体情况进行分析，从而得到合适的解决方案。</p>

<p><strong>关于作者</strong></p>

<p>GcsSloop，一名 2.5 次元魔法师。</p>

    <hr>
  </section>
</article>

<!--捐赠晶石-->
<section class="contribute">
    <script type="text/javascript"> 
      function toggle() {
        var con = document.getElementById("contribute");
        if (con.style.display == "none") {
          con.style.display = "block";
        } else {
          con.style.display = "none";
        }
      }
    </script> 
    <blockquote style="background-color:#F5F5F5; padding: 10px 20px 20px 10px; margin:0px" >
      <h4> 如果你觉得我的文章对你有帮助的话，捐赠一些晶石! </h4>
      <p></p>
      <a class="btn-contribute" onclick="toggle()" >¥ 捐赠晶石</a>
      <br>
      <div id="contribute" style="display:none;">
        <p align="center" >
        <img src="/assets/images/wechat.png" alt="微信">
        <img src="/assets/images/alipay.png" alt="支付宝">
        </p>
        <p align="center" >
          感谢所有支持我的魔法师。
          <!--
          <a href="/contribute">点击这里查看捐赠者名单。</a>
          -->
        </p>
      </div>
    </blockquote>
</section>
<div>
  <h2>欢迎关注我的微信公众号</h2>
  <img src="/assets/images/banner.jpg" width="100%">
</div>

<!--阅读更多-->
<section class="read-more">
  
   
   
   
   <div class="read-more-item">
       <span class="read-more-item-dim">更早的文章</span>
       <h2 class="post-list__post-title post-title"><a href="/gebug/rclayout" title="link to 雕虫晓技(三) 通用圆角布局全解析">雕虫晓技(三) 通用圆角布局全解析</a></h2>
       <p class="excerpt">关于作者GcsSloop，一名 2.5 次元魔法师。微博 | GitHub | 博客1. 前言之前，我在 GitHub 分享了一个开源库：rclayout，这个库的主要目的是快速实现 Andro...&hellip;</p>
       <div class="post-list__meta">
          <time datetime="2017-12-29 00:00:00 +0800" class="post-list__meta--date date">2017-12-29</time> &#8226; <span class="post-list__meta--tags tags">GeBug</span>
          <br/><br/>
          <a style="float:none; margin:0 auto;" class="btn-border-small" href=/gebug/rclayout>继续阅读</a>
       </div>
   </div>
   
</section>

<!--网易云跟帖-->
<!--
<div id="cloud-tie-wrapper" class="cloud-tie-wrapper"></div>
<script src="https://img1.cache.netease.com/f2e/tie/yun/sdk/loader.js"></script>
<script>
var cloudTieConfig = {
  url: document.location.href, 
  sourceId: "",
  productKey: "a85dba2840134721a7b69a15b2e0f217",
  target: "cloud-tie-wrapper"
};
var yunManualLoad = true;
Tie.loader("aHR0cHM6Ly9hcGkuZ2VudGllLjE2My5jb20vcGMvbGl2ZXNjcmlwdC5odG1s", true);
</script>
-->


<!--
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
-->
<!-- OneV's Den -->
<!--
<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-3324997515191619"
     data-ad-slot="9170309685"
     data-ad-format="auto"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
-->

            <section class="footer">
    <footer>
    	<span class="footer__copyright">本站点采用<a rel="license" href="https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh" target="_blank">知识共享 署名-非商业性使用-禁止演绎 4.0 国际 许可协议</a></span>
        <span class="footer__copyright">本站由 <a href="http://www.GcsSloop.com">@GcsSloop</a> 创建，采用 <a href="https://github.com/GcsSloop/Gcs-Vno-Jekyll" target="_blank">Gcs-Vno-Jekyll</a> 作为主题。<span id="busuanzi_container_site_pv"> 总访问量 <span id="busuanzi_value_site_pv"></span> 次</span> - &copy; 2018</span>
        <span class="footer__sitemap, footer__copyright"><a href="http://www.gcssloop.com/sitemap.xml" target="_blank">Site Map</a></span>
    </footer>
</section>

        </div>
    </div>
    
    <script type="text/javascript" src="//code.jquery.com/jquery-1.11.3.min.js"></script>

<script type="text/javascript" src="/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

<script type="text/javascript" src="/js/main.js"></script>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-82493667-1', 'auto');
  ga('send', 'pageview');

</script>

    
  </body>

</html>
